package com.onadake.web.controller;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.onadake.domain.query.Criterium;
import com.onadake.utils.DomainUtils;
import com.onadake.utils.ValidationUtils;
import com.onadake.web.domain.RequestErrors;
import com.onadake.web.domain.UserFilterColumns;
import com.onadake.web.domain.UserProfile;
import com.onadake.web.service.HumanVerificationService;
import com.onadake.web.service.UserService;

/**
 * Controller which is responsible for registration.
 * 
 * @author radek.hecl
 *
 */
@Controller
@RequestMapping("/register")
public class RegistrationController {

    /**
     * Builder object.
     */
    public static class Builder {

        /**
         * Service for verifying whether user is human or not.
         */
        private HumanVerificationService humanVerificationService;
        
        /**
         * Service for user management.
         */
        private UserService userService;
        
        /**
         * Sets service for verifying whether user is human or not. 
         * 
         * @param humanVerificationService service for verifying whether user is human or not
         * @return this instance
         */
        public Builder setHumanVerificationService(HumanVerificationService humanVerificationService) {
            this.humanVerificationService = humanVerificationService;
            return this;
        }
        
        /**
         * Builds the result object.
         * 
         * @return created object
         */
        public RegistrationController build() {
            return new RegistrationController(this);
        }
    }

    /**
     * Service for verifying whether user is human or not.
     */
    @Autowired
    private HumanVerificationService humanVerificationService;

    /**
     * Service for user management.
     */
    @Autowired
    private UserService userService;

    
    /**
     * Constructor to allow frameworks create new instances.
     */
    @SuppressWarnings("unused")
    private RegistrationController() {
    }
    
    /**
     * Creates new instance.
     * 
     * @param builder
     */
    public RegistrationController(Builder builder) {
        humanVerificationService = builder.humanVerificationService;
        userService = builder.userService;
        guardInvariants();
    }
    
    /**
     * Guards this object to be consistent. Throws exception if this is not the case.
     */
    @PostConstruct
    public void guardInvariants() {
        ValidationUtils.guardNotNull(humanVerificationService, "humanVerificationService cannot be null");
        ValidationUtils.guardNotNull(userService, "userService cannot be null");
    }
    
    /**
     * Returns view name of the registration page
     * 
     * @return view name of the registration page
     */
    @RequestMapping(method = RequestMethod.GET)
    public String getRegistrationPageView() {
        return "register";
    }

    /**
     * Processes the registration.
     * Returns empty JSON object on success or error JSON in case of validation failure.
     * 
     * @return empty JSON object on success or error JSON in case of validation failure
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public Object processRegistration(@ModelAttribute RegistrationModel model) {
        if (!humanVerificationService.isHuman(model.getHumanCheck())) {
            return new RequestErrors.Builder().
                    addNamedFieldError("AYAH", "Please prove you are a human").
                    build();
        }
        UserProfile profile = model.getUserProfile();
        if (userService.countUsers(DomainUtils.createSet(Criterium.createEqual(UserFilterColumns.E_MAIL, profile.getEmail()))) > 0) {
            return new RequestErrors.Builder().
                    addNamedFieldError("email", "Already in use").
                    build();
        }
        userService.insertUser(profile, model.getPassword());
        return "{}";
    }
    
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
    
}
